package com.huangfu.learning.javabase.java.pattern.action.template;

/**
 * Created with IntelliJ IDEA.
 * Author: huangfu.daohui
 * Date: 2018/8/8
 * Time: 10:11
 * Version: 1.0
 * Description:模板方法模式 ：定义一个模板结构，将具体内容延迟到子类去实现。
 * https://blog.csdn.net/carson_ho/article/details/54910518
 * <p>
 * 主要作用：
 * 在不改变模板结构的前提下在子类中重新定义模板中的内容。模板方法模式是基于”继承“的；
 * 解决的问题：
 * 提高代码复用性
 * 将相同部分的代码放在抽象的父类中，而将不同的代码放入不同的子类中
 * 实现了反向控制
 * 通过一个父类调用其子类的操作，通过对子类的具体实现扩展不同的行为，实现了反向控制 & 符合“开闭原则”
 * <p>
 * 实例概况
 * 背景：小成希望学炒菜：手撕包菜 & 蒜蓉炒菜心
 * 冲突：两道菜的炒菜步骤有的重复有的却差异很大，记不住
 * 解决方案：利用代码记录下来
 **/

/**
 * 步骤三：客户端调用炒菜类
 */
public class TemplateMethod {
    public static void main(String[] args) {

        // 炒包菜
        ConcreteClassBaoCai baoCai = new ConcreteClassBaoCai();
        System.out.println("炒包菜流程如下：");
        baoCai.cookProcess();

        System.out.println("");
        // 炒菜心
        ConcreteClassCaiXin caiXin = new ConcreteClassCaiXin();
        System.out.println("炒菜心流程如下：");
        caiXin.cookProcess();
    }
}

/**
 * 第一步：创建抽象模板结构（Abstract Class）：炒菜的步骤
 * 封装不变的步骤，抽象可变的步骤
 */
abstract class AbstractStep {
    //模板方法，用来控制炒菜的流程 （炒菜的流程是一样的-复用）
    //申明为final，不希望子类覆盖这个方法，防止更改流程的执行顺序
    final void cookProcess() {
        //第一步：倒油
        this.pourOil();
        //第二步：热油
        this.HeatOil();
        //第三步：倒蔬菜
        this.pourVegetable();
        //第四步：倒调味料
        this.pourSauce();
        //第五步：翻炒
        this.fry();
    }
    //定义结构里哪些方法是所有过程都是一样的可复用的，哪些是需要子类进行实现的

    //第一步：倒油是一样的，所以直接实现
    void pourOil() {
        System.out.println("倒油");
    }

    //第二步：热油是一样的，所以直接实现
    void HeatOil() {
        System.out.println("热油");
    }

    //第三步：倒蔬菜是不一样的（一个下包菜，一个是下菜心）
    //所以声明为抽象方法，具体由子类实现
    abstract void pourVegetable();

    //第四步：倒调味料是不一样的（一个下辣椒，一个是下蒜蓉）
    //所以声明为抽象方法，具体由子类实现
    abstract void pourSauce();


    //第五步：翻炒是一样的，所以直接实现
    void fry() {
        System.out.println("炒啊炒啊炒到熟啊");
    }

}

/**
 * 步骤2： 创建具体模板（Concrete Class）,即”手撕包菜“和”蒜蓉炒菜心“的具体步骤
 */
//炒手撕包菜的类
class ConcreteClassBaoCai extends AbstractStep {

    @Override
    void pourVegetable() {
        System.out.println("下锅的是手撕包菜");
    }

    @Override
    void pourSauce() {
        System.out.println("下锅的酱料是辣椒");
    }
}

//炒蒜蓉菜心的类
class ConcreteClassCaiXin extends AbstractStep {

    @Override
    void pourVegetable() {
        System.out.println("下锅的菜是菜心");
    }

    @Override
    void pourSauce() {
        System.out.println("下锅的酱料是蒜蓉");
    }
}


